#!/usr/bin/env python3
"""共用常數與函數"""
import hashlib
import os
import re
import shutil

try:
    # officially supported since Python 3.8
    from functools import cached_property
except ImportError:
    from cached_property import cached_property  # noqa: F401

import yaml

HTML_VOID_ELEMENTS = {
    'area',
    'base',
    'br',
    'col',
    'embed',
    'hr',
    'img',
    'input',
    'link',
    'meta',
    'param',
    'source',
    'track',
    'wbr',
    'frame',
}

# ref: https://gist.github.com/ArjanSchouten/0b8574a6ad7f5065a5e7
HTML_BOOLEAN_ATTRIBUTES = {
    'async',
    'autocomplete',
    'autofocus',
    'autoplay',
    'border',
    'challenge',
    'checked',
    'compact',
    'contenteditable',
    'controls',
    'default',
    'defer',
    'disabled',
    'formnovalidate',
    'frameborder',
    'hidden',
    'indeterminate',
    'inlist',
    'ismap',
    'itemscope',
    'loop',
    'multiple',
    'muted',
    'nohref',
    'noresize',
    'noshade',
    'novalidate',
    'nowrap',
    'open',
    'readonly',
    'required',
    'reversed',
    'scoped',
    'scrolling',
    'seamless',
    'selected',
    'sortable',
    'spellcheck',
    'translate',
}

REGEX_ASCII_WHITESPACES = re.compile(r'[ \t\n\r\f]+')

REGEX_HTML_ESCAPE = re.compile(r"""[&<>"']| (?= )""")

DEFAULT_CONFIG_FILE = 'config.yaml'


def html_escape(text, dquote=True, squote=False, space=False):
    """跳脫 HTML 字元"""
    html_escape_table = {
        '&': '&amp;',
        '>': '&gt;',
        '<': '&lt;',
        '"': '&quot;' if dquote else '"',
        "'": '&apos;' if squote else "'",
        ' ': '&nbsp;' if space else ' ',
    }

    return REGEX_HTML_ESCAPE.sub(lambda m: html_escape_table[m.group(0)], text)


def fread(file):
    r"""將 UTF-8 檔案載入為文字

    - 去除 BOM
    - 統一換行為 '\n'
    """
    with open(file, 'r', encoding='UTF-8-SIG') as fh:
        content = fh.read()
    return content


def fwrite(file, content):
    r"""將文字儲存為 UTF-8 檔案

    - 自動建立上層資料夾
    - 不更動換行（'\n' 原樣輸出）
    """
    os.makedirs(os.path.dirname(file), exist_ok=True)
    with open(file, 'w', encoding='UTF-8', newline='') as fh:
        fh.write(content)


def fcopy(fsrc, fdst):
    """複製檔案

    - 自動建立上層資料夾
    """
    os.makedirs(os.path.dirname(fdst), exist_ok=True)
    shutil.copyfile(fsrc, fdst)


def fchecksum(file, hasher=hashlib.sha256, chunk_size=8192):
    """計算檔案的校驗值"""
    m = hasher()
    with open(file, 'rb') as fh:
        for chunk in iter(lambda: fh.read(chunk_size), b''):
            m.update(chunk)
    return m.hexdigest()


def is_relative_to(path, ref):
    """測試 path 是否位於 ref 以下的路徑。

    - 參見 PurePath.is_relative_to
    """
    rel = os.path.relpath(os.path.abspath(path), os.path.abspath(ref))
    return not (rel == os.pardir or rel.startswith(os.pardir + os.sep))


def load_config(file):
    """載入 YAML 配置檔"""
    try:
        fh = open(file, 'r', encoding='UTF-8-SIG')
    except FileNotFoundError:
        return {}

    with fh as fh:
        conf = yaml.safe_load(fh)

    return conf
